# tag.py
"""Define Tag class to hold a dicom (group, element) tag"""
# Copyright (c) 2013 Darcy Mason
# This file is part of pydicom, released under a modified MIT license.
#    See the file license.txt included with this distribution, also
#    available at http://pydicom.googlecode.com

# Store the 4 bytes of a dicom tag as a (group, elem) pair


from collections import namedtuple

NamedTag = namedtuple("NamedTag", "group element")


class Tag(NamedTag):
    """Tag object built around namedtuple"""
    # Note __slots__ not possible for tuple subclass
    tag_format = "({tag[0]:04x}, {tag[1]:04x})"

    def __new__(cls, group, element):
        if group <= 0xFFFF and element <= 0xFFFF:
            return NamedTag.__new__(cls, group, element)
        raise(OverflowError, "Group and element must be <=2 byte integers")

    @classmethod
    def fromlong(cls, val):
        return cls(val >> 16, val & 0xffff)

    @property
    def is_private(self):
        """Return True if the tag is private (odd group number), else False"""
        return self[0] & 1

    def __str__(self):
        """String of tag value as per Tag.tag_format, default '(gggg, eeee)'"""
        return self.tag_format.format(tag=self)

    __repr__ = __str__

    # for backwards compatibility, provide alternate access to 'elem'
    @property
    def elem(self):
        return self[1]

    def __eq__(self, other):
        # Override underlying tuple comparison, for backwards compatibility
        # with pydicom < 1, where comparison against an int or list was allowed
        # Costs approx factor 5 in speed vs tuple, but still quite fast
        try:
            return self[0] == other[0] and self[1] == other[1]
        except TypeError:
            try:
                return tuple.__eq__(self, Tag.fromlong(other))
            except:
                raise TypeError("Can only compare Tag with tuple or int/long")

    def __ne__(self, other):
        try:
            return self[0] != other[0] or self[1] != other[1]
        except TypeError:
            try:
                return tuple.__ne__(self, Tag.fromlong(other))
            except:
                raise TypeError("Can only compare Tag with tuple or int/long")

    def __lt__(self, other):
        try:
            return self[0] < other[0] or (self[0] == other[0]
                                          and self[1] < other[1])
        except TypeError:
            try:
                return tuple.__lt__(self, Tag.fromlong(other))
            except:
                raise TypeError("Can only compare Tag with tuple or int/long")

    def __le__(self, other):
        try:
            return self[0] < other[0] or (self[0] == other[0]
                                          and self[1] <= other[1])
        except TypeError:
            try:
                return tuple.__le__(self, Tag.fromlong(other))
            except:
                raise TypeError("Can only compare Tag with tuple or int/long")

    def __gt__(self, other):
        try:
            return self[0] > other[0] or (self[0] == other[0]
                                          and self[1] > other[1])
        except TypeError:
            try:
                return tuple.__gt__(self, Tag.fromlong(other))
            except:
                raise TypeError("Can only compare Tag with tuple or int/long")

    def __ge__(self, other):
        try:
            return self[0] > other[0] or (self[0] == other[0]
                                          and self[1] >= other[1])
        except TypeError:
            try:
                return tuple.__ge__(self, Tag.fromlong(other))
            except:
                raise TypeError("Can only compare Tag with tuple or int/long")

# Define some special tags:
# See PS 3.5-2008 section 7.5 (p.40)
ItemTag = Tag(0xFFFE, 0xE000)  # start of Sequence Item
ItemDelimiterTag = Tag(0xFFFE, 0xE00D)  # end of Sequence Item
SequenceDelimiterTag = Tag(0xFFFE, 0xE0DD)  # end of Sequence of undefined length
